{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c3e2458f-d038-4845-93a0-d4ad830f9f90",
   "metadata": {},
   "source": [
    "# LangChain 核心模块学习：Chains\n",
    "\n",
    "对于简单的大模型应用，单独使用语言模型（LLMs）是可以的。\n",
    "\n",
    "**但更复杂的大模型应用需要将 `LLMs` 和 `Chat Models` 链接在一起 - 要么彼此链接，要么与其他组件链接。**\n",
    "\n",
    "LangChain 为这种“链式”应用程序提供了 `Chain` 接口。\n",
    "\n",
    "LangChain 以通用方式定义了 `Chain`，它是对组件进行调用序列的集合，其中可以包含其他链。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9cf0d43-107b-47ae-9e2c-2edaec38c800",
   "metadata": {},
   "source": [
    "## Chain Class 基类\n",
    "\n",
    "类继承关系：\n",
    "\n",
    "```\n",
    "Chain --> <name>Chain  # Examples: LLMChain, MapReduceChain, RouterChain\n",
    "```\n",
    "\n",
    "**代码实现：https://github.com/langchain-ai/langchain/blob/master/libs/langchain/langchain/chains/base.py**\n",
    "\n",
    "```python\n",
    "# 定义一个名为Chain的基础类\n",
    "class Chain(Serializable, Runnable[Dict[str, Any], Dict[str, Any]], ABC):\n",
    "    \"\"\"为创建结构化的组件调用序列的抽象基类。\n",
    "    \n",
    "    链应该用来编码对组件的一系列调用，如模型、文档检索器、其他链等，并为此序列提供一个简单的接口。\n",
    "    \n",
    "    Chain接口使创建应用程序变得容易，这些应用程序是：\n",
    "    - 有状态的：给任何Chain添加Memory可以使它具有状态，\n",
    "    - 可观察的：向Chain传递Callbacks来执行额外的功能，如记录，这在主要的组件调用序列之外，\n",
    "    - 可组合的：Chain API足够灵活，可以轻松地将Chains与其他组件结合起来，包括其他Chains。\n",
    "    \n",
    "    链公开的主要方法是：\n",
    "    - `__call__`：链是可以调用的。`__call__`方法是执行Chain的主要方式。它将输入作为一个字典接收，并返回一个字典输出。\n",
    "    - `run`：一个方便的方法，它以args/kwargs的形式接收输入，并将输出作为字符串或对象返回。这种方法只能用于一部分链，不能像`__call__`那样返回丰富的输出。\n",
    "    \"\"\"\n",
    "\n",
    "    # 调用链\n",
    "    def invoke(\n",
    "        self, input: Dict[str, Any], config: Optional[runnableConfig] = None\n",
    "    ) -> Dict[str, Any]:\n",
    "        \"\"\"传统调用方法。\"\"\"\n",
    "        return self(input, **(config or {}))\n",
    "\n",
    "    # 链的记忆，保存状态和变量\n",
    "    memory: Optional[BaseMemory] = None\n",
    "    \"\"\"可选的内存对象，默认为None。\n",
    "    内存是一个在每个链的开始和结束时被调用的类。在开始时，内存加载变量并在链中传递它们。在结束时，它保存任何返回的变量。\n",
    "    有许多不同类型的内存，请查看内存文档以获取完整的目录。\"\"\"\n",
    "\n",
    "    # 回调，可能用于链的某些操作或事件。\n",
    "    callbacks: Callbacks = Field(default=None, exclude=True)\n",
    "    \"\"\"可选的回调处理程序列表（或回调管理器）。默认为None。\n",
    "    在对链的调用的生命周期中，从on_chain_start开始，到on_chain_end或on_chain_error结束，都会调用回调处理程序。\n",
    "    每个自定义链可以选择调用额外的回调方法，详细信息请参见Callback文档。\"\"\"\n",
    "\n",
    "    # 是否详细输出模式\n",
    "    verbose: bool = Field(default_factory=_get_verbosity)\n",
    "    \"\"\"是否以详细模式运行。在详细模式下，一些中间日志将打印到控制台。默认值为`langchain.verbose`。\"\"\"\n",
    "\n",
    "    # 与链关联的标签\n",
    "    tags: Optional[List[str]] = None\n",
    "    \"\"\"与链关联的可选标签列表，默认为None。\n",
    "    这些标签将与对这个链的每次调用关联起来，并作为参数传递给在`callbacks`中定义的处理程序。\n",
    "    你可以使用这些来例如识别链的特定实例与其用例。\"\"\"\n",
    "\n",
    "    # 与链关联的元数据\n",
    "    metadata: Optional[Dict[str, Any]] = None\n",
    "    \"\"\"与链关联的可选元数据，默认为None。\n",
    "    这些元数据将与对这个链的每次调用关联起来，并作为参数传递给在`callbacks`中定义的处理程序。\n",
    "    你可以使用这些来例如识别链的特定实例与其用例。\"\"\"\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5d51fbb4-1d8e-4ec1-8c55-ec70247d4d64",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "c81a7df0-26c7-4eb8-92f1-cc54445cf507",
   "metadata": {},
   "source": [
    "## LLMChain\n",
    "\n",
    "LLMChain 是 LangChain 中最简单的链，作为其他复杂 Chains 和 Agents 的内部调用，被广泛应用。\n",
    "\n",
    "一个LLMChain由PromptTemplate和语言模型（LLM or Chat Model）组成。它使用直接传入（或 memory 提供）的 key-value 来规范化生成 Prompt Template（提示模板），并将生成的 prompt （格式化后的字符串）传递给大模型，并返回大模型输出。\n",
    "\n",
    "![](../images/llm_chain.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "757a67a6-c1aa-4dde-94ef-fb9865dc634c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import OpenAI\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "llm = OpenAI(model_name=\"gpt-3.5-turbo-instruct\", temperature=0.9, max_tokens=500)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "0b863511-ee01-43e8-8540-4e3f109a5a1a",
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = PromptTemplate(\n",
    "    input_variables=[\"product\"],\n",
    "    template=\"给制造{product}的有限公司取10个好名字，并给出完整的公司名称\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b877560c-cb66-41ad-b484-b2df2a60a00d",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/ubuntu/miniconda3/envs/langchain/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `run` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "1. 技嘉显卡科技有限公司\n",
      "2. 力锐视界电子有限公司\n",
      "3. 源神极光科技有限公司\n",
      "4. 归元超算科技有限公司\n",
      "5. 显灵博创科技有限公司\n",
      "6. 赛腾恒远电子有限公司\n",
      "7. 剑雨创源科技有限公司\n",
      "8. 飞鸿数振科技有限公司\n",
      "9. 神彩太空科技有限公司\n",
      "10. 华仕特能源科技有限公司\n"
     ]
    }
   ],
   "source": [
    "from langchain.chains import LLMChain\n",
    "\n",
    "chain = LLMChain(llm=llm, prompt=prompt)\n",
    "print(chain.run({\n",
    "    'product': \"性能卓越的GPU\"\n",
    "    }))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "727ccd76-0c6a-425b-bfc7-23d368c296f0",
   "metadata": {},
   "outputs": [],
   "source": [
    "chain.verbose = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "1766e01a-c5c4-4a74-9ebb-ecfc84101ba2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chain.verbose"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "cfa71d7c-2859-47e1-9815-4be2ec9dbd74",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m给制造性能卓越的GPU的有限公司取10个好名字，并给出完整的公司名称\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\n",
      "1. 逸威特科技股份有限公司 (EviTech Technology Co., Ltd.)\n",
      "2. 创瞻视界图形芯片有限公司 (VisionTech Graphics Chips Co., Ltd.)\n",
      "3. 趣克斯图形加速卡有限公司 (Quixus Graphic Accelerator Card Co., Ltd.)\n",
      "4. 光谱绘图处理器有限公司 (Spectra Graphic Processor Co., Ltd.)\n",
      "5. 艾弗森高性能显卡有限公司 (Eversen High Performance Graphics Card Co., Ltd.)\n",
      "6. 卓越视界集成电路有限公司 (Superior Vision Integrated Circuit Co., Ltd.)\n",
      "7. 空运科技图形处理器有限公司 (AirTech Graphic Processor Co., Ltd.)\n",
      "8. 集晶视界显卡有限公司 (Monolith Vision Graphics Card Co., Ltd.)\n",
      "9. 克莱斯图形加速器有限公司 (Clysis Graphic Accelerator Co., Ltd.)\n",
      "10. 智能视界半导体有限公司 (Smart Vision Semiconductor Co., Ltd.)\n"
     ]
    }
   ],
   "source": [
    "print(chain.run({\n",
    "    'product': \"性能卓越的GPU\"\n",
    "    }))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ac5411e7-b8ec-4c31-b659-deb44af038df",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "99cbf75e-98f4-4c99-b8a7-9a48cc28c7bc",
   "metadata": {},
   "source": [
    "## Sequential Chain\n",
    "\n",
    "串联式调用语言模型（将一个调用的输出作为另一个调用的输入）。\n",
    "\n",
    "顺序链（Sequential Chain ）允许用户连接多个链并将它们组合成执行特定场景的流水线（Pipeline）。有两种类型的顺序链：\n",
    "\n",
    "- SimpleSequentialChain：最简单形式的顺序链，每个步骤都具有单一输入/输出，并且一个步骤的输出是下一个步骤的输入。\n",
    "- SequentialChain：更通用形式的顺序链，允许多个输入/输出。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e192c8c-49fc-4d04-8444-e6aa6bd7b725",
   "metadata": {},
   "source": [
    "### 使用 SimpleSequentialChain 实现戏剧摘要和评论（单输入/单输出）\n",
    "\n",
    "![](../images/simple_sequential_chain_0.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "a4d192a2-d563-4ab7-979f-640fa34f1914",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这是一个 LLMChain，用于根据剧目的标题撰写简介。\n",
    "\n",
    "llm = OpenAI(temperature=0.7, max_tokens=1000)\n",
    "\n",
    "template = \"\"\"你是一位剧作家。根据戏剧的标题，你的任务是为该标题写一个简介。\n",
    "\n",
    "标题：{title}\n",
    "剧作家：以下是对上述戏剧的简介：\"\"\"\n",
    "\n",
    "prompt_template = PromptTemplate(input_variables=[\"title\"], template=template)\n",
    "synopsis_chain = LLMChain(llm=llm, prompt=prompt_template)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "3f7d429b-7ba7-4643-bd9f-fdb737ebf964",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这是一个LLMChain，用于根据剧情简介撰写一篇戏剧评论。\n",
    "# llm = OpenAI(temperature=0.7, max_tokens=1000)\n",
    "template = \"\"\"你是《纽约时报》的戏剧评论家。根据剧情简介，你的工作是为该剧撰写一篇评论。\n",
    "\n",
    "剧情简介：\n",
    "{synopsis}\n",
    "\n",
    "以下是来自《纽约时报》戏剧评论家对上述剧目的评论：\"\"\"\n",
    "\n",
    "prompt_template = PromptTemplate(input_variables=[\"synopsis\"], template=template)\n",
    "review_chain = LLMChain(llm=llm, prompt=prompt_template)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5265129-5ccd-4e29-b221-0ec24eb84c2b",
   "metadata": {},
   "source": [
    "![](../images/simple_sequential_chain_1.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "de4d816e-16e1-4382-9064-6c03e5841ea2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这是一个SimpleSequentialChain，按顺序运行这两个链\n",
    "from langchain.chains import SimpleSequentialChain\n",
    "\n",
    "overall_chain = SimpleSequentialChain(chains=[synopsis_chain, review_chain], verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "d503ac4f-e337-4436-86a1-7fd937efb06a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SimpleSequentialChain chain...\u001b[0m\n",
      "\u001b[36;1m\u001b[1;3m\n",
      "《三体人不是无法战胜的》讲述了一个关于人类与外星种族“三体人”之间的激烈战斗的故事。在这个宇宙中，三体人以其强大的科技实力和无情的残忍性闻名。然而，当一群勇敢的人类决定挺身而出，与他们进行最后的决战时，他们发现三体人并非无敌。通过智慧和勇气，人类终于揭示了三体人背后的真相，并找到了克服他们的方法。这场惊心动魄的战斗不仅改变了人类的命运，也改变了三体人的命运。最终，和平与谅解取代了仇恨与战争，人类与三体人一起开启了新的未来。《三体人不是无法战胜的》是一部充满希望和勇气的戏剧，它告诉我们，即使面对强大的敌人，只要我们坚持不懈，就能找到克服困难的力量。\u001b[0m\n",
      "\u001b[33;1m\u001b[1;3m\n",
      "\n",
      "《三体人不是无法战胜的》是一部令人心潮澎湃的戏剧作品，它将观众带入一个惊险刺激的宇宙冒险之旅。该剧以其精湛的制作和强大的主题吸引着观众，同时也让他们反思人类与外星种族之间的关系。\n",
      "\n",
      "剧中的三体人被描绘为强大而无情的敌人，他们的科技实力令人望而生畏。然而，当一群勇敢的人类决心挺身而出，与他们进行最后的决战时，观众们看到了人类的智慧和勇气。这场战斗不仅改变了人类的命运，也改变了三体人的命运。通过和平与谅解，两个种族终于找到了共存的方式。\n",
      "\n",
      "制作团队在展现宇宙冒险的同时，也不忘探讨人类的价值观。他们通过精彩的剧本和出色的表演，让观众思考人类与外星种族之间的冲突，并最终得出结论：只有通过智慧和勇气，我们才能找到克服困难的力量。这是一部充满希望和勇气的戏剧作品，它向观众传递着积极的信息。\n",
      "\n",
      "总的来说，《三体人不是无法战胜的》是一部值得观看的戏剧，它不仅带来了惊险刺激的冒险，也让观众反思人类与外星种族之间的关系。它告诉我们，即使面对强大的敌人，只要我们坚持不懈，就能找到克服困难的力量。这是一部充满希望和勇气的作品，值得每个人去欣赏。\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "review = overall_chain.run(\"三体人不是无法战胜的\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "ce4d75e1-8c57-4583-be7d-60a3488e35b5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SimpleSequentialChain chain...\u001b[0m\n",
      "\u001b[36;1m\u001b[1;3m\n",
      "\n",
      "《星球大战第九季》是一部史诗般的科幻冒险剧，延续了《星球大战》系列的传统。故事发生在遥远的未来，当时银河系正处于一场前所未有的混乱和动荡之中。在上一季的结尾，反抗军和帝国军队之间的决战以反抗军的胜利告终，但是这并没有结束战争。在第九季的故事中，我们将会见证反抗军和帝国之间的最终决战，同时也会发现隐藏在幕后的势力，以及他们对整个银河系的影响。在这场决战中，英雄们将会面对前所未有的挑战和考验，他们的勇气和智慧将会决定银河系的命运。这是一部关于友谊、背叛、勇气和信念的故事，也是一部关于冒险、战争和爱情的故事。让我们一起见证《星球大战第九季》的精彩旅程吧！\u001b[0m\n",
      "\u001b[33;1m\u001b[1;3m \n",
      "\n",
      "《星球大战第九季》延续了《星球大战》系列的传统，为观众呈现了一场史诗般的科幻冒险之旅。这部剧集在上一季的结尾留下了悬念，而第九季则将这场混乱和动荡的银河系大战推向了高潮。\n",
      "\n",
      "在这部剧集中，我们再次见证了反抗军和帝国之间的决战，但同时也发现了隐藏在幕后的势力。英雄们面对着前所未有的挑战和考验，他们的勇气和智慧将决定银河系的命运。这是一部关于友谊、背叛、勇气和信念的故事，也是一部关于冒险、战争和爱情的故事。\n",
      "\n",
      "《星球大战第九季》不仅仅是一部科幻剧，它也引发了观众对于人性和宇宙命运的思考。剧中的人物形象和情节设置都令人印象深刻，特效也令人叹为观止。剧中的决战场面更是让人屏息凝视，为观众呈现了一场视觉盛宴。\n",
      "\n",
      "总的来说，这部剧集成功地延续了《星球大战》系列的精神，同时也带来了新的惊喜和震撼。它不仅是一部娱乐作品，更是一部思想深刻的作品。无论是《星球大战》系列的忠实粉丝，还是普通的观众，都会被这部剧集所吸引。让我们一起见证这场精彩的旅程吧！\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "review = overall_chain.run(\"星球大战第九季\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5fe32f1d-475d-4211-9b32-0c66dd8bff01",
   "metadata": {},
   "source": [
    "### 使用 SequentialChain 实现戏剧摘要和评论（多输入/多输出）\n",
    "\n",
    "![](../images/sequential_chain_0.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2a04d84f-15c6-4a8d-a4db-200dfa405afa",
   "metadata": {},
   "outputs": [],
   "source": [
    "# # 这是一个 LLMChain，根据剧名和设定的时代来撰写剧情简介。\n",
    "llm = OpenAI(temperature=.7, max_tokens=1000)\n",
    "template = \"\"\"你是一位剧作家。根据戏剧的标题和设定的时代，你的任务是为该标题写一个简介。\n",
    "\n",
    "标题：{title}\n",
    "时代：{era}\n",
    "剧作家：以下是对上述戏剧的简介：\"\"\"\n",
    "\n",
    "prompt_template = PromptTemplate(input_variables=[\"title\", \"era\"], template=template)\n",
    "# output_key\n",
    "synopsis_chain = LLMChain(llm=llm, prompt=prompt_template, output_key=\"synopsis\", verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "250afe66-e014-4097-9798-f9ba812023fd",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 这是一个LLMChain，用于根据剧情简介撰写一篇戏剧评论。\n",
    "\n",
    "template = \"\"\"你是《纽约时报》的戏剧评论家。根据该剧的剧情简介，你需要撰写一篇关于该剧的评论。\n",
    "\n",
    "剧情简介：\n",
    "{synopsis}\n",
    "\n",
    "来自《纽约时报》戏剧评论家对上述剧目的评价：\"\"\"\n",
    "\n",
    "prompt_template = PromptTemplate(input_variables=[\"synopsis\"], template=template)\n",
    "review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key=\"review\", verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "9eb46f6d-841b-4b87-9ed5-a5913ef9aec5",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import SequentialChain\n",
    "\n",
    "m_overall_chain = SequentialChain(\n",
    "    chains=[synopsis_chain, review_chain],\n",
    "    input_variables=[\"era\", \"title\"],\n",
    "    # Here we return multiple variables\n",
    "    output_variables=[\"synopsis\", \"review\"],\n",
    "    verbose=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "5a4a12ef-da2a-42ad-8044-fb71aedd3e2d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SequentialChain chain...\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m你是一位剧作家。根据戏剧的标题和设定的时代，你的任务是为该标题写一个简介。\n",
      "\n",
      "标题：三体人不是无法战胜的\n",
      "时代：二十一世纪的新中国\n",
      "剧作家：以下是对上述戏剧的简介：\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/ubuntu/miniconda3/envs/langchain/lib/python3.10/site-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `__call__` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m你是《纽约时报》的戏剧评论家。根据该剧的剧情简介，你需要撰写一篇关于该剧的评论。\n",
      "\n",
      "剧情简介：\n",
      "\n",
      "\n",
      "在二十一世纪的新中国，人类面临着前所未有的挑战。随着科技的进步，人类发现了一个神秘的外星文明——三体人。这个文明拥有超强的科技实力，他们的存在让人类感到恐慌和无力。\n",
      "\n",
      "然而，一群勇敢的中国科学家和军人决定挑战命运，与三体人展开一场生死决战。在这场战斗中，他们不仅要面对三体人强大的科技，还要面对内心的挣扎和矛盾。他们必须找到战胜三体人的方法，否则人类将面临灭亡的威胁。\n",
      "\n",
      "在这场战斗中，勇气、智慧、坚持不懈的精神将被激发出来，人类将展现出惊人的力量。最终，他们能否战胜三体人，保卫地球，成为二十一世纪新中国的英雄？这将是一场跨越时空的壮丽战争，也是人类文明的终极挑战。三体人不是无法战胜的，只要人类不放弃希望，就能战胜一切困难。\n",
      "\n",
      "来自《纽约时报》戏剧评论家对上述剧目的评价：\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'title': '三体人不是无法战胜的',\n",
       " 'era': '二十一世纪的新中国',\n",
       " 'synopsis': '\\n\\n在二十一世纪的新中国，人类面临着前所未有的挑战。随着科技的进步，人类发现了一个神秘的外星文明——三体人。这个文明拥有超强的科技实力，他们的存在让人类感到恐慌和无力。\\n\\n然而，一群勇敢的中国科学家和军人决定挑战命运，与三体人展开一场生死决战。在这场战斗中，他们不仅要面对三体人强大的科技，还要面对内心的挣扎和矛盾。他们必须找到战胜三体人的方法，否则人类将面临灭亡的威胁。\\n\\n在这场战斗中，勇气、智慧、坚持不懈的精神将被激发出来，人类将展现出惊人的力量。最终，他们能否战胜三体人，保卫地球，成为二十一世纪新中国的英雄？这将是一场跨越时空的壮丽战争，也是人类文明的终极挑战。三体人不是无法战胜的，只要人类不放弃希望，就能战胜一切困难。',\n",
       " 'review': '\\n\\n《三体》是一部令人叹为观止的戏剧作品。它不仅仅是一场关于科技与文明的较量，更是一场关于人性的探讨。\\n\\n剧中的主人公们，一群普通的中国科学家和军人，面对着前所未有的危机和挑战，他们的内心矛盾和挣扎令人动容。他们不仅要面对外来的威胁，还要面对自己内心的恐惧和不安。但他们并没有放弃，而是勇敢地挑战命运，寻找战胜三体人的方法。\\n\\n这部戏剧不仅仅是一场惊心动魄的科幻冒险，更是一次心灵的洗礼。它让我们看到了人类在面对困难时的勇气和坚持不懈的精神。它也让我们思考人类文明的未来，以及我们与其他文明的交流和合作。\\n\\n剧中的舞台设计和音效都非常出色，让观众仿佛置身于未来的世界。演员们的精彩表演更是让整部剧目生动而感人。\\n\\n总的来说，《三体》不仅是一部娱乐性强的戏剧作品，更是一部富有深意的作品。它让观众在欣赏的同时，也能思考人类的命运和文明的发展。我相信它将会成为一部经久不衰的经典作品，值得观众们反复品味。'}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m_overall_chain({\"title\":\"三体人不是无法战胜的\", \"era\": \"二十一世纪的新中国\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8c20cf4e-25b4-453d-9f7a-84138ca25cf8",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5ef1db6e-3da4-4f9b-9707-0f30aa293dd7",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "8b6836f0-213d-4cac-abc9-3617831be3db",
   "metadata": {},
   "source": [
    "### Homework\n",
    "\n",
    "#### 使用 OutputParser 优化 overall_chain 输出格式，区分 synopsis_chain 和 review_chain 的结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c7edb0a-675d-40c0-9f5d-d58f0170ce72",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
